{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "colab": {
   "name": "AI-GA_Meta-Evolution_Demo.ipynb",
   "provenance": [],
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": { "name": "python" }
 },
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 🧬 AI-GA Meta-Evolution · Colab\n",
    "\n",
    "Fully-featured notebook that spins up the **three-pillar** demo from Clune (2020) in ~2 minutes.\n",
    "\n",
    "**What you get**\n",
    "1. 📦 Minimal runtime install (CPU ⬅️ default, GPU optional)\n",
    "2. 🔑 Optional `OPENAI_API_KEY` for LLM commentary (offline Mixtral otherwise)\n",
    "3. 🚀 `agent_aiga_entrypoint.py` exposing:\n",
    "   * Gradio dashboard → port `7862` (public HTTPS link auto-printed)\n",
    "   * FastAPI JSON API → port `8000` (see `/docs`)\n",
    "4. 🧪 Unit-test cell (`pytest -q`) – target **≥ 90 % branch coverage** < 0.5 s\n",
    "5. 📈 Inline Prometheus scrape & Matplotlib plot\n",
    "6. 🤖 Example REST calls (evolve / checkpoint) using `httpx`"
   ]
  },
  {
   "cell_type": "code",
   "metadata": { "id": "00_gpu_flag" },
   "source": [
    "#@title ↳ Choose runtime {display-mode: \"form\"}\n",
    "USE_GPU = False  #@param {type:\"boolean\"}\n",
    "print(\"⚙️  GPU runtime\" if USE_GPU else \"⚙️  CPU runtime\")"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "code",
   "metadata": { "id": "01_setup" },
   "source": [
    "# ↳ Setup (≈90 s CPU / 60 s GPU) -----------------------------------------\n",
    "%%bash --no-stderr\n",
    "set -Eeuo pipefail\n",
    "\n",
    "# clone\n",
    "if [[ ! -d AGI-Alpha-Agent-v0 ]]; then\n",
    "  echo \"📡  Cloning Alpha-Factory repo …\" >&2\n",
    "  git clone --depth 1 https://github.com/MontrealAI/AGI-Alpha-Agent-v0.git -q\n",
    "fi\n",
    "cd AGI-Alpha-Agent-v0/alpha_factory_v1/demos/aiga_meta_evolution\n",
    "\n",
    "# wheel index depending on GPU flag\n",
    "WHL_URL=\"https://download.pytorch.org/whl/$(python - <<PY\n",
    "import json, os; print('cu118' if os.environ.get('USE_GPU','False')=='True' else 'cpu')\n",
    "PY)\"\n",
    "\n",
    "echo \"📦  Installing deps …\" >&2\n",
    "pip -q install --upgrade pip\n",
    "pip -q install torch torchvision --extra-index-url $WHL_URL\n",
    "pip -q install gymnasium[classic_control] gradio==4.* openai_agents httpx prometheus-client pytest coverage"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "code",
   "metadata": { "id": "02_key" },
   "source": [
    "# ↳ (optional) supply OpenAI key ------------------------------------------\n",
    "import os, getpass, textwrap\n",
    "\n",
    "if not os.getenv(\"OPENAI_API_KEY\"):\n",
    "    key = getpass.getpass(\"Paste OPENAI_API_KEY, or press Enter for offline mode: \")\n",
    "    if key:\n",
    "        %env OPENAI_API_KEY=$key\n",
    "        print(\"🔑  Key set – online mode.\")\n",
    "    else:\n",
    "        print(\"🛰️  Offline mode (Mixtral via Ollama cloud binary).\")"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "code",
   "metadata": { "id": "03_tests" },
   "source": [
    "# ↳ Quick unit tests -------------------------------------------------------\n",
    "%%bash\n",
    "cd AGI-Alpha-Agent-v0/alpha_factory_v1/demos/aiga_meta_evolution\n",
    "pytest -q || echo \"⚠️  Tests failed – demo still launchable but investigate!\""
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "code",
   "metadata": { "id": "04_launch" },
   "source": [
    "# ↳ Launch the orchestration service & dashboard --------------------------\n",
    "import subprocess, threading, re, time, sys, pathlib, os, json\n",
    "\n",
    "ROOT = pathlib.Path(\"AGI-Alpha-Agent-v0/alpha_factory_v1/demos/aiga_meta_evolution\").resolve()\n",
    "os.chdir(ROOT)\n",
    "\n",
    "proc = subprocess.Popen([sys.executable, \"agent_aiga_entrypoint.py\"],\n",
    "                        stdout=subprocess.PIPE, stderr=subprocess.STDOUT,\n",
    "                        text=True)\n",
    "\n",
    "public = None\n",
    "def _tail():\n",
    "    global public\n",
    "    for line in proc.stdout:\n",
    "        print(line, end=\"\")\n",
    "        if not public and \"Running on\" in line and \"https\" in line:\n",
    "            public = re.search(r\"https?://[\\w./-]+\", line)[0]\n",
    "            print(f\"\\n🔗  Dashboard → {public}\\n\")\n",
    "threading.Thread(target=_tail, daemon=True).start()\n",
    "\n",
    "for _ in range(90):\n",
    "    if public: break\n",
    "    time.sleep(1)\n",
    "if not public:\n",
    "    print(\"⏳  Still starting … open logs above for status.\")"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ☎️ Interact with the JSON API"
   ]
  },
  {
   "cell_type": "code",
   "metadata": { "id": "05_api" },
   "source": [
    "import httpx, time, pandas as pd, matplotlib.pyplot as plt\n",
    "\n",
    "API = \"http://localhost:8000\"\n",
    "print(httpx.get(API + \"/health\").json())\n",
    "\n",
    "# schedule 20 generations asynchronously\n",
    "httpx.post(API + \"/evolve/20\").json()"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "code",
   "metadata": { "id": "06_metrics" },
   "source": [
    "# ↳ scrape Prometheus metrics & plot --------------------------------------\n",
    "import re, json, pandas as pd, matplotlib.pyplot as plt, httpx, time\n",
    "\n",
    "raw = httpx.get(API + \"/metrics\").text\n",
    "fitness = float(re.search(r\"aiga_best_fitness (\\d+\\.?\\d*)\", raw).group(1))\n",
    "gen     = int(re.search(r\"aiga_generations_total (\\d+)\", raw).group(1))\n",
    "print(f\"Generation {gen}, best fitness {fitness:.2f}\")"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 📊 Plot fitness history\n",
    "The checkpoint JSON embeds the `(generation, avg_fitness)` list."
   ]
  },
  {
   "cell_type": "code",
   "metadata": { "id": "07_plot" },
   "source": [
    "import json, pathlib, matplotlib.pyplot as plt, pandas as pd, glob\n",
    "ckpt = sorted(glob.glob(\"checkpoints/evolver_gen*.json\"))[-1]\n",
    "hist = json.loads(pathlib.Path(ckpt).read_text())[\"history\"]\n",
    "df = pd.DataFrame(hist, columns=[\"gen\", \"avg\"])\n",
    "df.plot(x=\"gen\", y=\"avg\", figsize=(6,3), grid=True, legend=False)"
   ],
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 🏗 Running on Kubernetes (FYI)\n",
    "```yaml\n",
    "apiVersion: apps/v1\n",
    "kind: Deployment\n",
    "metadata: { name: aiga-demo }\n",
    "spec:\n",
    "  replicas: 1\n",
    "  selector: { matchLabels: { app: aiga-demo } }\n",
    "  template:\n",
    "    metadata: { labels: { app: aiga-demo } }\n",
    "    spec:\n",
    "      containers:\n",
    "      - name: orchestrator\n",
    "        image: ghcr.io/montrealai/alpha-aiga:latest@sha256:<signed>\n",
    "        envFrom:\n",
    "        - secretRef: { name: aiga-secrets }\n",
    "        ports:\n",
    "        - containerPort: 8000\n",
    "        - containerPort: 7862\n",
    "```\n",
    "Full SOC-2 artefacts (audit logs, SBOM, cosign signature) ship with the container."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 🎯 Next steps\n",
    "* Increase `pop_size` or enable GPU for faster evolution.\n",
    "* Modify `curriculum_env.py` to add novel stages.\n",
    "* Plug the JSON API into your own micro-services for autonomous decision loops."
   ]
  }
 ]
}
